package com.pubinfo.passbook.engine.process.equation;

import com.pubinfo.passbook.common.entity.TEnginePlaceholderEquation;
import com.pubinfo.passbook.common.model.http.engine.ComputeParam;
import com.pubinfo.passbook.common.service.aviator.AviatorScriptService;
import com.pubinfo.passbook.engine.constants.ComputeChainType;
import com.pubinfo.passbook.engine.constants.ComputeParamType;
import com.pubinfo.passbook.engine.constants.ComputeResultType;
import com.pubinfo.passbook.engine.process.ParamenterProcessor;
import com.pubinfo.passbook.common.utils.ApplicationContextUilts;
import com.pubinfo.passbook.engine.utils.ValidateUtils;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 公式处理器内部可以套用变量处理器
 * <p>
 * 公式处理器: 公式计算只能已数值型为结果
 */
@Slf4j
public class EquationProcessor<T> extends ParamenterProcessor<T, BigDecimal> {

    private AviatorScriptService aviatorScriptService;

    protected Collection<? extends ParamenterProcessor<T, BigDecimal>> processors;

    /**
     * 内部参数列表
     */
    protected Collection<ComputeParam> paramList;

    /**
     * 公式体
     */
    protected String equationBody;

    private String description;

    public EquationProcessor(TEnginePlaceholderEquation equationInfo) {
        this(equationInfo.getBody(), equationInfo.getParamList(), equationInfo.getDescription());
    }

    public EquationProcessor(String equationBody, Collection<ComputeParam> paramList, String description) {
        this.paramList = paramList;
        this.equationBody = equationBody;
        this.description = description;
        aviatorScriptService = ApplicationContextUilts.getBean(AviatorScriptService.class);
    }

    @Override
    public String getName() {
        return "公式";
    }

    @Override
    public BigDecimal get(T data) {

        // 将所有参数处理器全部执行, 以占位符为Key, 参数处理器执行结果为Value
        Map<String, Object> realPlaceholderValue = processors.stream()
                .peek(
                        // 设置缓存
                        it -> it.setCache(cache)
                )
                .collect(Collectors.toMap(
                        // 占位符名称为Key
                        ParamenterProcessor::getPlaceHolderName,
                        // 真实值为Value
                        value -> value.get(data)));

        log.info("开始执行公式: {}, 参数:{}", equationBody, realPlaceholderValue);

        outputComputeMessage(  equationBody + " 描述: " + description);

        // 执行公式, 并且填入上面所有参数处理器执行后的占位符的真实值
        return aviatorScriptService.execute(equationBody, realPlaceholderValue);
    }

    @Override
    public String getResultType() {
        return ComputeResultType.NUMBER;
    }

    @Override
    public String getChainType() {
        return ComputeChainType.COMMON;
    }

    @Override
    public String getType() {
        return ComputeParamType.EQUATION;
    }

    /**
     * 设置参数处理器, 并且检查参数列表和参数插槽是否匹配
     *
     * @param processors
     */
    public void setProcessors(Collection<? extends ParamenterProcessor<?, ?>> processors) {

        this.processors = (Collection<? extends ParamenterProcessor<T, BigDecimal>>) processors;

        // 检查参数列表和参数处理器是否匹配
        ValidateUtils.checkComputeParamProcessorAvailable(paramList, processors);
    }
}
